package cn.spring.framework.redis.core.redis;

import cn.spring.framework.redis.config.LzmhRedisProperties;
import cn.spring.framework.redis.constant.Constants;
import cn.spring.framework.redis.core.FillCache;
import cn.spring.framework.redis.core.ListOperator;
import cn.spring.framework.redis.core.Refresher;
import cn.spring.framework.redis.excutor.AsyncCacheExecutor;
import cn.spring.framework.redis.excutor.CacheExecutor;
import cn.spring.framework.redis.excutor.FutureAdapter;
import cn.spring.framework.redis.excutor.SyncCacheExecutor;
import cn.spring.framework.redis.service.RedisService;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
 * @author xingkong
 * @Title: RedisListOperator
 * @Description: list类型操作实现
 * @date 2021/11/15 9:17
 */
public class RedisListOperator extends AbstractRedisOperator implements ListOperator {

    /**
     * 异步任务执行器
     */
    protected CacheExecutor<List<String>> asyncCacheExecutor = new AsyncCacheExecutor<>();

    public RedisListOperator(LzmhRedisProperties lzmhRedisProperties, RedisService redisService) {
        super(lzmhRedisProperties, redisService);
    }

    @Override
    public List<String> lRange(String key, long start, long end, long expire, Refresher<List<String>> refresher) {
        return this.lRange(key, start, end, expire, refresher, new SyncCacheExecutor<>()).getData();
    }

    @Override
    public String lPop(String key, long expire, Refresher<List<String>> refresher) {
        List<String> lrange = this.lRange(key, 0, 0, expire, refresher, new SyncCacheExecutor<>()).getData();
        String res = null;
        if (!CollectionUtils.isEmpty(lrange)) {
            res = lrange.get(0);
        }
        return res;
    }

    @Override
    public String rPop(String key, long expire, Refresher<List<String>> flusher) {
        List<String> lrange = this.lRange(key, -1, -1, expire, flusher, new SyncCacheExecutor<>()).getData();
        String res = null;
        if (!CollectionUtils.isEmpty(lrange)) {
            res = lrange.get(0);
        }
        return res;
    }

    @Override
    public Future<List<String>> lRangeAsync(String key, long start, long end, long expire, Refresher<List<String>> flusher) {
        return this.lRange(key, start, end, expire, flusher, this.asyncCacheExecutor);
    }

    @Override
    public Future<List<String>> lRangeAsync(String key, long start, long end, long expire, Refresher<List<String>> flusher, ExecutorService executorService) {
        return this.lRange(key, start, end, expire, flusher, new AsyncCacheExecutor<>(executorService));
    }

    @Override
    public Future<List<String>> lPopAsync(String key, long expire, Refresher<List<String>> flusher) {
        return this.lRange(key, 0, 0, expire, flusher, this.asyncCacheExecutor);
    }

    @Override
    public Future<List<String>> lPopAsync(String key, long expire, Refresher<List<String>> flusher, ExecutorService executorService) {
        return  this.lRange(key, 0, 0, expire, flusher, new AsyncCacheExecutor<>(executorService));
    }

    @Override
    public Future<List<String>> rPopAsync(String key, long expire, Refresher<List<String>> flusher) {
        return  this.lRange(key, -1, -1, expire, flusher, this.asyncCacheExecutor);
    }

    @Override
    public Future<List<String>> rPopAsync(String key, long expire, Refresher<List<String>> flusher, ExecutorService executorService) {
        return  this.lRange(key, -1, -1, expire, flusher, new AsyncCacheExecutor<>(executorService));
    }

    private FutureAdapter<List<String>> lRange(String key, long start, long end, long expire, Refresher<List<String>> refresher,
                                               CacheExecutor<List<String>> cacheExecutor) {
        List<String> res = redisService.getCacheList(key, start, end);
        if (!CollectionUtils.isEmpty(res)) {
            return FutureAdapter.runAndGetFuture(res);
        }

        //缓存过期获取缓存中无数据，刷新缓存
        return (FutureAdapter<List<String>>) cacheExecutor.executor(() -> this.fillCache(new FillCache<List<String>>() {
            @Override
            public String getKey() {
                return key;
            }

            @Override
            public List<String> getIgnoreValidData() {
                List<String> list = (List<String>) blockIfNeed(key);
                if (CollectionUtils.isEmpty(list)) {
                    return redisService.getCacheList(key, start, end);
                }
                return list;
            }

            @Override
            public List<String> getCacheData() {
                //执行具体的获取缓存数据逻辑
                List<String> data = refresher.refresh();
                if (data == null) {
                    data = new ArrayList<>();
                }
                //对过期时间进行延长
                long newExpire = expire;
                if (expire != Constants.REDIS_TTL_FOREVER) {
                    newExpire = getExtendExpire(expire);
                }
                //填充缓存
                redisService.setCacheList(key, newExpire, data);
                return data;
            }
        }));
    }

    @Override
    protected Object getDataIgnoreValid(String key) {
        boolean exists = redisService.hasKey(key);
        if (exists) {
            return Constants.EMPTY_LIST;
        }
        return null;
    }
}
